# -*- coding: utf-8 -*-
import jsonpath
from utils.log.logger import logger
from codes.hjt_assertion.assert_expr import AssertExpr


class BasicAssert:
    # 断言函数的后缀，如 equal_assert函数
    OPERATOR_SUFFIX = '_assert'

    def __init__(self, ass_expr: dict, suffix_response, suffix_request_args):
        self.ass_expr = ass_expr
        self.operator, self.expr = map(lambda item: item[0], zip(*ass_expr.items()))
        self.suffix_response = suffix_response
        self.suffix_request_args = suffix_request_args
        self.expect_val = None
        self.actual_val = None
        self.ERROR_MSG = None
        self.fail_flags = 0
        self._hot_expr()

    def expr_check(self):
        """e.g.
            - equals: { code: 200 }
            - equals: { msg: success }
            - contains: {$response.area: ''}
            - equals: {$s_upper($response.nickname): SHARK}
        :return: fail_flags
        """
        # 运算符equals、表达式{code:OK}
        try:
            operator_func = getattr(self, self.operator + self.OPERATOR_SUFFIX)
        except AttributeError:
            self.ERROR_MSG = f"框架不支持此断言【{self.operator + self.OPERATOR_SUFFIX}】"
            raise Exception(self.ERROR_MSG)
        try:
            flag = operator_func()
            self.fail_flags += flag
            ass_log_msg = f"{self.operator + '断言结果:【$msg】':<20}|实际值: {self.actual_val:<15} ▉预期值: {self.expect_val:<15} ▉" \
                          f"表达式: {self.ass_expr}."
            if not flag:
                ass_log_msg = ass_log_msg.replace('$msg', 'PASS')
            else:
                ass_log_msg = ass_log_msg.replace('$msg', 'FAIL')
            logger.info(ass_log_msg)
        except Exception:
            raise

        return self.fail_flags

    def _hot_expr(self):
        """
        一个断言表达式中，替换预期结果、实际结果
        :return: key_, value_, fail_flag
        """
        suffix_response = self.suffix_response.json()
        for key, value in self.expr.items():
            # 处理预期结果
            value_ = AssertExpr(value, self.suffix_request_args, suffix_response).main()
            # 处理实际结果
            if key == 'status_code':
                key_ = self.suffix_response.status_code
            elif key.startswith('$'):
                key_ = AssertExpr(key, self.suffix_request_args, suffix_response).main()
            else:
                key_ = jsonpath.jsonpath(suffix_response, "$..%s" % key)[0]
            # 实际响应字段提取不到 (会返回False), 则断言失败;
            # 提取的是空字符串，则传递给运算符函数
            if not key_ and key_ != '':
                self.fail_flags += 1
                self.ERROR_MSG = f"断言失败，表达式{self.expr}: 响应结果中没有{key}"
                logger.info(self.ERROR_MSG)
                raise AssertionError(self.ERROR_MSG)
            # 若预期值、实际值替换成功，则保存
            self.expect_val = value_
            self.actual_val = key_

    def codes_assert(self):
        ...

    def equals_assert(self):
        ...

    def contains_assert(self):
        ...

    def database_assert(self):
        ...
